package com.hrt.datasender.datacollect.drive.modbus.rtu;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.btcode.exception.MsgException;
import com.btcode.schedule.ScheduleManager;
import com.hrt.datasender.datacollect.drive.DriveBase;
import com.hrt.datasender.datacollect.drive.DriveConfigModel;
import com.hrt.datasender.datacollect.drive.DriveParameterMetadata;
import com.hrt.datasender.datadao.model.BcDevicesModel;
import com.hrt.datasender.datadao.model.BdSourceModel;
import com.hrt.datasender.mq.MqKit;
import com.hrt.datasender.mq.MqKit.MsgListener;
import com.hrt.datasender.mq.model.MqModel;
import com.hrt.datasender.mq.model.SerialModel;

/**
 * 2018年1月22日
 * 此类继承DriveBase，注册串口数据询问定时器，并实现监听消息队列中的串口消息，其中解析数据的方法processSerialData，留给子类实现
 * 
 * @author gislin
 *
 */
public abstract class ModbusSerialBaseDrive extends DriveBase {

    /**
     * 注册消息监听，调用子类的processSerialData方法解析数据
     */
    protected void registerMQListener(BcDevicesModel device, HashMap<Integer, String> paramCodeMap,
            DriveConfigModel configs) {

        MqKit.consumeMsgFromSerialMQ(device, new MsgListener() {

            @Override
            public void onReceive(MqModel mqModel) {

                SerialModel model = (SerialModel) mqModel;

                List<BdSourceModel> datas = processSerialData(model.getData(), paramCodeMap, configs);
                log.info("数据解析成功，size:" + datas.size());
                setSourceData(datas);
            }
        });
    }

    /**
     * 注册数据询问定时任务，这里使用 {@link ModbusSerialDataAsker} 作为定时器 <br>
     * 定时器不能通过构造函数传参，只能通过构造HashMap<String, Object>的方式进行传参
     */
    protected void registerAskDataJob(BcDevicesModel device, DriveConfigModel configs) {
        HashMap<String, Object> data = new HashMap<>();

        data.put("device", device);
        data.put("deviceConfigs", configs);
        String consStr = configs.getConfig().get("consStr");

        if (consStr == null || consStr.equals("")) {
            throw new MsgException("请设置数据询问时间间隔");
        }

        String jobName = getClass().getName() + "." + device.getId();

        ScheduleManager.getInstance().addJob(ModbusSerialDataAsker.class, consStr, data, jobName);
    }

    /**
     * 从设备中获取原始数据
     * 
     * @return
     */
    public abstract List<BdSourceModel> processSerialData(byte[] data, HashMap<Integer, String> paramCodeMap,
            DriveConfigModel configs);

    @Override
    public List<DriveParameterMetadata> getParameterMetadata() {

        List<DriveParameterMetadata> params = new ArrayList<>();
        params.add(new DriveParameterMetadata("consStr", "数据询问时间规则（0/10 * * * * ?）"));
        params.add(new DriveParameterMetadata("slaveNo", "从站编号"));
        params.add(new DriveParameterMetadata("startNo", "数据读取位置"));
        params.add(new DriveParameterMetadata("dataLength", "数据读取长度(如果是32位，数据长度要x2)"));
        params.add(new DriveParameterMetadata("dataBit", "数据位（8,16,32,32HL）"));
        params.add(new DriveParameterMetadata("functionCode", "功能码(1,2,3,4)"));
        return params;
    }
}
